#include "tablefuncs.h"

using std::string;
using std::cout;
using std::cerr;

extern string limit;   
    
void printTable(SymbolTable *table)
{    
    if (table == 0)
    {
        cout << "Module does not export any names" << std::endl;
        return;
    }
    
    while (table != 0)
    {
        if (nameInLimit(table->name))
        {
            printType(table->symbolType);
            cout << "\t";
            printModifiers(table->modifiers);
            cout << "\t";
            printInternal(table->internal);
            cout << "\t";
            printName(table->name);
            if (table->symbolType == Func || table->symbolType == Constructor)
            {
                cout << " (";
                NameList *nl = table->argumentTypes;
                while (nl != 0)
                {
                    printName(nl->name);
                    if (nl->next != 0)
                    {
                        cout << ", ";
                        
                    }
                    nl = nl->next;
                }
                cout << ")";
            }
            cout << std::endl;
        }
        table = table->next;
    }
}

void printTableForCache(SymbolTable *table)
{    
    if (table == 0)
    {
        cout << "" << std::endl;
        return;
    }
    
    while (table != 0)
    {
        if (nameInLimit(table->name))
        {
            printType2(table->symbolType);
            cout << "\t";
            printName(table->name);
            cout << "\n";
        }
        table = table->next;
    }
}

void printSymbolTable(SymbolTable *table)
{    
    if (table == 0)
    {
        cout << "" << std::endl;
        return;
    }
    
    while (table != 0)
    {
        if (nameInLimit(table->name))
        {
            printType2(table->symbolType);
            cout << "\t";
            cout << table->modifiers;
            cout << "\t";
            printInternal2(table->internal);
            cout << "\t";
            printName(table->type);
            cout << "\t";
            printName(table->name);
            if (table->symbolType == Func || table->symbolType == Constructor)
            {
                cout << "(";
                NameList *nl = table->argumentTypes;
                while (nl != 0)
                {
                    printName(nl->name);
                    if (nl->next != 0)
                    {
                        cout << ",";
                        
                    }
                    nl = nl->next;
                }
                cout << ")";
            }
            cout << "\n";
        }
        table = table->next;
    }
}

void printName(Name *name)
{
    using std::cout;
    using std::cerr;   
    
    if (name == 0)
    {
        cout << "(unnamed)";
        return;
    }
    
    while (name != 0)
    {
        cout << name->identifier;
        if (name->next > 0)
            cout << ".";
        name = name->next;
    }
}

void printType(SymbolType type)
{
    using std::cout;
    using std::cerr;   
    
    switch (type)
    {
        case Var:
            cout << "variable   ";
            break;
        case Func:
            cout << "function   ";
            break;
        case Class:
            cout << "class      ";
            break;
        case Constructor:
            cout << "constructor";
            break;
        case Operator:
            cout << "operator   ";
            break;
        default:
        case Unknown:
            cout << "unknown    ";
            break;
    }
}

void printType2(SymbolType type)
{
    using std::cout;
    using std::cerr;   
    
    switch (type)
    {
        case Var:
            cout << "0";
            break;
        case Func:
            cout << "1";
            break;
        case Class:
            cout << "2";
            break;
        case Constructor:
            cout << "3";
            break;
        case Operator:
            cout << "4";
            break;
        default:
        case Unknown:
            cout << "-";
            break;
    }
}

void printModifiers(int modifiers)
{
    if (modifiers & FLAG_PUBLIC)
        cout << "PU ";
    if (modifiers & FLAG_PROTECTED)
        cout << "PR ";
    if (modifiers & FLAG_PRIVATE)
        cout << "PV ";
    if (modifiers & FLAG_STATIC)
        cout << "S "; 
    if (modifiers & FLAG_ABSTRACT)
        cout << "A ";
    if (modifiers & FLAG_FINAL)
        cout << "F ";
}

void printInternal(char *internal)
{
    cout << internal;
    int extra = 16 - strlen(internal);
    for (int i = 0; i < extra; i++)
        cout << " ";
}

void printInternal2(char *internal)
{
    cout << internal;
}

int compareNames(Name *name1, Name *name2)
{
    if (name1 == 0)
        return -2;
    if (name2 == 0)
        return 2;
    while (strcmp(name1->identifier, name2->identifier) == 0)
    {
        if (name1->next == 0 && name2->next == 0)
            return 0;
        if (name1->next == 0 && name2->next != 0)
            return -1;
        if (name1->next != 0 && name2->next == 0)
            return 1;
        name1 = name1->next;
        name2 = name2->next;        
    }
    return strcmp(name1->identifier, name2->identifier);
}

string getInternalFromName(SymbolTable *table, Name *name)
{
    if (strcmp(name->identifier, "int") == 0 && name->next == 0)
        return "int";
    if (strcmp(name->identifier, "float") == 0 && name->next == 0)
        return "float";
    if (strcmp(name->identifier, "bool") == 0 && name->next == 0)
        return "short int";
    if (strcmp(name->identifier, "byte") == 0 && name->next == 0)
        return "char";
    if (strcmp(name->identifier, "char") == 0 && name->next == 0)
        return "char";
    if (strcmp(name->identifier, "long") == 0 && name->next == 0)
        return "long int";
    if (strcmp(name->identifier, "double") == 0 && name->next == 0)
        return "double";
    if (strcmp(name->identifier, "short") == 0 && name->next == 0)
        return "short int";
    
    if (table == 0)
    {
        cout << "Module does not export any names" << std::endl;
        return "";
    }
    
    while (table != 0)
    {
        if (compareNames(name, table->name) == 0)
            return string(table->internal);
        table = table->next;
    }
    cerr << "Name not found!" << std::endl;
    return "";
}

string nameToString(Name *name)
{
    string str = "";
    
    while (name != 0)
    {
        str += name->identifier;
        if (name->next != 0)
            str += ".";
        name = name->next;
    }
    
    return str;
}

bool nameInLimit(Name *name)
{
    if (limit == "")
        return true;
    return nameToString(name).find(limit) == 0;
}


